'''
Udp的通信协议代码：包括了作为客户端或者服务端的接收数据和发送数据
以及获取本地IP的方法
'''

import socket
import threading
from PyQt5.QtCore import pyqtSignal



def get_host_ip() -> str:
    '''
    获取本机ip地址
    :return:返回的是IP地址
    '''
    try:
        s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #AF_INET:IPV4的地址簇，SOCK_DGRAM：使用udp协议
        s.connect(("8.8.8.8",80))
        ip = s.getsockname()[0]     #获取这个套接字的本地地址：ip地址和端口号信息
    finally:
        s.close()
    return ip


class UdpLogic:
    '''
    udp的逻辑代码
    '''
    udp_signal_write_msg = pyqtSignal(str)              #定义消息信号
    udp_signal_write_info = pyqtSignal(str,int)         #定义发送文件信号

    def __init__(self):
        '''
        初始化
        '''
        self.link_flag = False                  #定义标志位
        self.udp_socket =None                   #定义UDP套接字
        self.address =None                      #定义地址
        self.server_th =None                    #定义服务端标志位
        self.client_th =None                    #定义客户端标志位

    def udp_server_start(self,port) -> None:
        '''
        开启UDP服务端
        :param port:端口号
        :return:
        '''
        self.udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)       #创建套接字
        port = int(port)                                                        #端口号
        address = ("",port)                                                     #地址
        self.udp_socket.bind(address)                                           #连接地址
        self.server_th =threading.Thread(target=self.udp_server_concurrency)    #创建udp服务端任务
        self.server_th.start()                                                  #启动

        msg = "UDP服务端正在监听端口：{}\n".format(port)
        self.udp_signal_write_msg.emit(msg)

    def udp_server_concurrency(self) -> None:
        '''
        监听udp通信的线程任务
        :return:
        '''
        while True:
            recv_msg, recv_addr = self.udp_socket.recvfrom(1024)  # 接收数据

            if '\\' in str(recv_msg):
                info = recv_msg.decode("gbk")  # 对接收数据的编码
            else:
                info = recv_msg.decode("utf-8")  # 对接收数据的编码
            msg = f"来自IP：{recv_addr[0]}端口：{recv_addr[1]}:"
            self.udp_signal_write_msg.emit(msg)
            self.udp_signal_write_info.emit(info, self.InfoRec)



    def udp_client_start(self,ip:str,port:int)->None:
        '''
        确认UDP客户端的ip及地址
        :param ip:客户端的ip
        :param port:客户端的端口号
        :return:
        '''
        self.udp_socket =socket.socket(socket.AF_INET,socket.SOCK_DGRAM)        #创建套接字
        self.address = (ip,port)                                                #绑定地址
        msg = "客户端已经启动\n"
        self.udp_signal_write_msg.emit(msg)

    def udp_send(self,send_info:str)->None:
        '''
        功能函数，用于UDP客户端发送消息
        :param send_info:需要发送的数据
        :return:
        '''
        try:
            send_info_encode = send_info.encode("utf-8")                #发送数据的编码
            self.udp_socket.sendto(send_info_encode,self.address)       #发送数据
            msg = "UDP客户端已发送\n"
            self.udp_signal_write_msg.emit(msg)
            self.udp_signal_write_info.emit(send_info,self.InfoSend)
        except  Exception as ret:
            msg = "发送失败\n"
            self.udp_signal_write_msg.emit(msg)

    def udp_close(self)->None:
        '''
        功能函数，关闭网络连接的方法
        :return:
        '''
        if self.link_flag == self.ServerUDP:
            try:
                self.udp_socket.close()                         #关闭端口
                msg = "已经断开网络\n"
                self.udp_signal_write_msg.emit(msg)
            except Exception as ret:
                pass
            try:
                StopThreading.stop_thread(self.server_th)
            except Exception as ret:
                pass

        if self.link_flag == self.ClientUDP:
            try:
                self.udp_socket.close()                 #关闭端口
                msg = "已经断开网络\n"
                self.udp_signal_write_msg.emit(msg)
            except Exception as ret:
                pass

            try:
                StopThreading.stop_thread(self.client_th)
            except Exception as ret:
                pass


    NoLink = -1
    ServerUDP =2
    ClientUDP =3
    InfoSend = 0
    InfoRec = 1



